#!/usr/bin/env python
#
# Copyright (c) 2008, Eric Chastain All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without 
# modification, are permitted provided that the following conditions 
# are met:
# 
# Redistributions of source code must retain the above copyright notice, 
# this list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice, 
# this list of conditions and the following disclaimer in the documentation 
# and/or other materials provided with the distribution.
# The name of the author may not be used to endorse or promote products 
# derived from this software without specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
# THE POSSIBILITY OF SUCH DAMAGE.

# Interesting thread, may help with my line ending problem
# http://groups.google.com/group/scintilla-interest/browse_thread/thread/ca6484c46c6462c3/be54f309738433d0#be54f309738433d0

# More ideas
# http://code.google.com/p/farmhand/source/diff?r=180&format=side&path=/trunk/src/modes.py

'''MU text editor - editor.py (subclassed stc)
'''
__author__ = 'mu@ericchastain.org (Eric Chastain)'

import keyword
import wx
import wx.stc as stc
import plistlib

class EditorControl(stc.StyledTextCtrl):

	def __init__(self, parent, p, style=wx.SIMPLE_BORDER):
		stc.StyledTextCtrl.__init__(self, parent, style=style)

		self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
		self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)

		self.SetProperty("fold", "1")
		self.SetProperty("tab.timmy.whinge.level", "1")

		self.SetIndent(4) # Number of indent columns

		#self.SetEOLMode(stc.STC_EOL_CR)
		self.SetEOLMode(stc.STC_EOL_CRLF)
		#self.SetMarginWidth(0, 35)
		#self.SetUseAntiAliasing(True)

		#self.SetEdgeMode(stc.STC_EDGE_BACKGROUND)
		#self.SetEdgeMode(stc.STC_EDGE_LINE)
		self.SetEdgeColumn(78)
		self.SetTabWidth(4)

		# ===================================================================

		self.Bind(stc.EVT_STC_UPDATEUI, 	p.OnUpdateUI)
		self.Bind(stc.EVT_STC_MARGINCLICK, 	self.OnMarginClick)
		self.Bind(wx.EVT_KEY_DOWN, 			p.onEditorKeyDown)
		self.Bind(wx.EVT_KEY_DOWN, 			self.OnKeyPressed)
		self.Bind(wx.EVT_KEY_UP, 			self.OnKeyUp)

		'''
		self.Bind(wx.EVT_IDLE, self._on_idle)
		self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
		self.Bind(wx.stc.EVT_STC_MODIFIED, self._on_change)
		self.Bind(wx.stc.EVT_STC_CHARADDED, self._on_new_char)
		self.Bind(wx.stc.EVT_STC_MARGINCLICK, self._on_margin_click)
		self.Bind(wx.stc.EVT_STC_UPDATEUI, self._on_update_ui)
		'''

		# buffer to store the string from the cursor to the previous char 32.
		# Is there a better way to do this than coding it myself in keypress?
		self.currentWord = ''

	def SetTheme(self, themePath, fileExtension):

		# ===================================================================
		# Load TextMate Themes (er, try to anyhow)
		# Load a TextMate theme.
		# ===================================================================

		# Get theme to load from configuration
		theme = plistlib.readPlist(themePath)

		# Theme Settings
		settings = theme["settings"]

		# Variables to hold values extracted from theme.
		caret_foreground = ''
		background = ''
		foreground = ''
		selection = ''
		invisibles_background = ''
		invisibles_foreground = ''
		lineHighlight = ''
		string_foreground = ''
		comment_foreground = ''
		keyword_foreground = ''
		text_foreground = ''
		function_foreground = ''
		classname_foreground = ''
		keyword_operator = ''
		string_background = ''
		comment_background = ''
		keyword_background = ''
		text_background = ''
		function_background = ''
		function_background = ''
		classname_background = ''
		keyword_operator_background = ''

		# set lexter and keyword list
		# setting keywords
		if fileExtension == '.py' or fileExtension == '.pyw':
			self.SetKeyWords(0, " ".join(keyword.kwlist))
			self.SetLexer(stc.STC_LEX_PYTHON)

		# http://www.wxpython.org/docs/api/wx.stc.StyledTextCtrl-class.html
		# Keywords bit IS NOT WORKING :)
		if fileExtension == '.html' or fileExtension == '.htm':

			#self.SetProperty("hypertext.elements", 'a abbr acronym address applet area b base basefont bdo big blockquote body br button caption center cite code col colgroup dd del dfn dir div dl dt em fieldset font form frame frameset h1 h2 h3 h4 h5 h6 head hr html i iframe img input ins isindex kbd label legend li link map menu meta noframes noscript object ol optgroup option p param pre q s samp script select small span strike strong style sub sup table tbody td textarea tfoot th thead title tr tt u ul var xml xmlns')
			#self.SetProperty("hypertext.attributes", 'abbr accept-charset accept accesskey action align alink alt archive axis background bgcolor border cellpadding cellspacing char charoff charset checked cite class classid clear codebase codetype color cols colspan compact content coords data datafld dataformatas datapagesize datasrc datetime declare defer dir disabled enctype event face for frame frameborder headers height href hreflang hspace http-equiv id ismap label lang language leftmargin link longdesc marginwidth marginheight maxlength media method multiple name nohref noresize noshade nowrap object onblur onchange onclick ondblclick onfocus onkeydown onkeypress onkeyup onload onmousedown onmousemove onmouseover onmouseout onmouseup onreset onselect onsubmit onunload profile prompt readonly rel rev rows rowspan rules scheme scope selected shape size span src standby start style summary tabindex target text title topmargin type usemap valign value valuetype version vlink vspace width text password checkbox radio submit reset file hidden image')
			#self.SetProperty("keywordclass.hypertext", "$(hypertext.elements) $(hypertext.attributes)")

			kwlist = [
			#--start keywords--
					'<html>',
					'head',
					'title',
					'body',
					'ol',
					'ul',
					'li',
					'table',
					'tr',
					'td',
					'style',
			#--end keywords--
					]

			
			#self.SetKeyWords(4, "$(keywordclass.hypertext)")
			#self.SetProperty("keywords.$(file.patterns.html)", "$(keywordclass.hypertext)")
			self.SetKeyWords(1, " ".join(kwlist))
			self.SetLexer(stc.STC_LEX_HTML)

			self.SetProperty("fold.html", "1") # WORKS!

		#if fileExtension == '.txt'
		#	self.SetLexer(stc.STC_LEX_PYTHON)

		# Pull color settings out of the theme file.
		# After this we map these settings to lexter properties
		# based on the current files extension, which isnt written very well right now.

		for setting in settings:
			try:
				name = self.clean(setting, "name")
				scope = self.clean(setting, "scope")
				item_settings = self.clean(setting, "settings")

				if scope == '':
					# Global Settings
					for item_setting in item_settings:
						if self.clean(item_settings, item_setting) <> '':
							if item_setting.lower() == 'caret': 		caret_foreground = self.clean(item_settings, item_setting)
							if item_setting.lower() == 'background':	background = self.clean(item_settings, item_setting)
							if item_setting.lower() == 'foreground':	foreground = self.clean(item_settings, item_setting)
							if item_setting.lower() == 'selection':		selection = self.clean(item_settings, item_setting)
							if item_setting.lower() == 'invisibles':	invisibles_background = self.clean(item_settings, item_setting)
							if item_setting.lower() == 'lineHighlight':	lineHighlight = self.clean(item_settings, item_setting)
				else:
					for item_setting in item_settings:
						if self.clean(item_settings, item_setting) <> '':

							if item_setting == 'foreground':
								if scope.lower() == 'string':   string_foreground = self.clean(item_settings, item_setting)
								if scope.lower() == 'comment':  comment_foreground = self.clean(item_settings, item_setting)
								if scope.lower() == 'keyword':  keyword_foreground = self.clean(item_settings, item_setting)
								if scope.lower() == 'text':     text_foreground = self.clean(item_settings, item_setting)
								if scope.lower() == 'entity.name.function': function_foreground = self.clean(item_settings, item_setting)
								if scope.lower() == 'entity.name.class' or 'entity.other.inherited-class': classname_foreground = self.clean(item_settings, item_setting)
								if scope.lower() == 'keyword.operator': keyword_operator = self.clean(item_settings, item_setting)

							if item_setting == 'background':
								if scope == 'string':   string_background = self.clean(item_settings, item_setting)
								if scope == 'comment':  comment_background = self.clean(item_settings, item_setting)
								if scope.lower() == 'keyword':  keyword_background = self.clean(item_settings, item_setting)
								if scope.lower() == 'text':     text_background = self.clean(item_settings, item_setting)
								if scope.lower() == 'entity.name.function': function_background = self.clean(item_settings, item_setting)
								if scope.lower() == 'entity.name.class' or 'entity.other.inherited-class': classname_background = self.clean(item_settings, item_setting)
								if scope.lower() == 'keyword.operator': keyword_operator_background = self.clean(item_settings, item_setting)

							# Fallback to defaults
							if invisibles_background == '': invisibles_background = background
							if invisibles_foreground == '': invisibles_foreground = foreground
							if selection == '': self.SetSelBackground(0, "")

							if string_background == '': string_background = background
							if comment_background == '': comment_background = background
							if keyword_background == '': keyword_background = background
							if text_background == '': text_background = background
							if function_background == '': function_background = background
							if function_background == '': function_background = background
							if classname_background == '': classname_background = background
							if keyword_operator_background == '': keyword_operator_background = background

					# Caret
					if caret_foreground <> '':
						self.SetCaretForeground(caret_foreground)
					else: # default caret color
						self.SetCaretForeground('#000000')

					# Highlighted text
					if selection <> '': self.SetSelBackground(1, selection)

					# Current line
					if lineHighlight <> '':
						self.SetCaretLineBackground(lineHighlight)
						self.SetCaretLineBackAlpha(50)
						self.SetCaretLineVisible(True)
					else:
						self.SetCaretLineVisible(False)

			except KeyError:
				pass

			# ===============================================================
			# Setup a margin to hold fold markers
			# ===============================================================

			# Margins - http://www.yellowbrain.com/stc/margins.html

			self.SetMargins(0,0) # Set left and right outer margins to 0 width
			lines = self.GetLineCount() # Get # of lines
			width = self.TextWidth(wx.stc.STC_STYLE_LINENUMBER,str(lines) + '   ')
			self.SetMarginWidth(0, width)

			#dont need this until i get started working on bookmarks
			self.SetMarginWidth(1, 0)   						# margin 1 for symbols, 16 px wide
			self.SetMarginType(1, wx.stc.STC_MARGIN_SYMBOL)		# 

			# Setup a margin to hold fold markers
			self.SetMarginType(2, wx.stc.STC_MARGIN_SYMBOL) # margin 2 for symbols
			self.SetMarginMask(2, wx.stc.STC_MASK_FOLDERS)  # set up mask for folding symbols
			self.SetMarginSensitive(2, True)           		# this one needs to be mouse-aware
			self.SetMarginWidth(2, 16)                 		# set margin 2 16 px wide

			# Fold Markers
			a = foreground
			b = background

			self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEREND,     wx.stc.STC_MARK_BOXPLUSCONNECTED,  a, b)
			self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPENMID, wx.stc.STC_MARK_BOXMINUSCONNECTED, a, b)
			self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERMIDTAIL, wx.stc.STC_MARK_TCORNER,  a, b)
			self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERTAIL,    wx.stc.STC_MARK_LCORNER,  a, b)
			self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERSUB,     wx.stc.STC_MARK_VLINE,    invisibles_foreground, invisibles_background) # green, orange
			self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDER,        wx.stc.STC_MARK_BOXPLUS,  a, b)
			self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPEN,    wx.stc.STC_MARK_BOXMINUS, invisibles_foreground, invisibles_background)


			# ===========================================================
			# Font Styles
			# Set up most available fonts here, allow user to change
			# and store this into their configuration file.
			# ? Does TextMate allow you to set this per tmTheme
			# or are these settings global ?
			# ===========================================================
			if wx.Platform == '__WXMSW__':
					self.faces = { 'times': 'Bitstream Vera Sans Mono',
										'mono' : 'Bitstream Vera Sans Mono',
										'helv' : 'Bitstream Vera Sans Mono',
										'other': 'Bitstream Vera Sans Mono',
										'size' : 10,
										'size2': 10,
									}
			elif wx.Platform == '__WXMAC__':
					self.faces = { 'times': 'Monaco',
										'mono' : 'Monaco',
										'helv' : 'Monaco',
										'other': 'Monaco',
										'size' : 12,
										'size2': 12,
									}
			else:
					self.faces = { 'times': 'Times',
										'mono' : 'Courier',
										'helv' : 'Helvetica',
										'other': 'new century schoolbook',
										'size' : 9,
										'size2': 9,
									}

			# ===========================================================
			# Colors
			# ===========================================================
			# Setup some default styles.
			self.StyleSetSpec(stc.STC_STYLE_DEFAULT,     "fore:" + foreground + ",back:" + background + ",face:%(helv)s,size:%(size)d" % self.faces)
			self.StyleClearAll()  # Reset all to be like the default
			self.StyleSetSpec(stc.STC_STYLE_DEFAULT,     "fore:" + foreground + ",back:" + background + ",face:%(helv)s,size:%(size)d" % self.faces)
			self.StyleSetSpec(stc.STC_STYLE_LINENUMBER,  "back:" + background + ",fore:" + foreground + ",face:%(helv)s,size:%(size2)d" % self.faces)
			self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, "back:" + background + ",fore:" + foreground + ",face:%(other)s" % self.faces)
			self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,  "back:" + background + ",fore:" + foreground + ",bold")
			self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,    "back:" + background + ",fore:" + foreground + ",bold")

			# Define the fold margin "checkerboard" colors.
			self.SetFoldMarginColour(1, background)
			self.SetFoldMarginHiColour(1, background)

			# Assign fonts and colors to elements

			# ===========================================================
			# Python Styles
			# ===========================================================
			if fileExtension == '.py' or fileExtension == '.pyw':

				#print('Styling as Python')

				# Default 
				self.StyleSetSpec(stc.STC_P_DEFAULT, "back:" + text_background + ",fore:" + text_foreground +" ,face:%(helv)s,size:%(size)d" % self.faces)
				# Comments
				self.StyleSetSpec(stc.STC_P_COMMENTLINE, "back:" + comment_background + ",fore:" + comment_foreground + ",face:%(other)s,size:%(size)d" % self.faces)
				# Number
				self.StyleSetSpec(stc.STC_P_NUMBER, "back:" + text_background + ",fore:" + text_foreground + ",size:%(size)d" % self.faces)
				# String
				self.StyleSetSpec(stc.STC_P_STRING, "back:" + string_background + ",fore:" + string_foreground + ",face:%(helv)s,size:%(size)d" % self.faces)
				# Single quoted string
				self.StyleSetSpec(stc.STC_P_CHARACTER, "back:" + string_background + ",fore:" + string_foreground + ",face:%(helv)s,size:%(size)d" % self.faces)
				# Keyword
				self.StyleSetSpec(stc.STC_P_WORD, "back:" + keyword_background + ",fore:" + keyword_foreground + ",bold,size:%(size)d" % self.faces)
				# Triple quotes
				self.StyleSetSpec(stc.STC_P_TRIPLE, "back:" + comment_background + ",fore:" + comment_foreground + ",size:%(size)d" % self.faces)
				# Triple double quotes
				self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, "back:" + comment_background + ",fore:" + comment_foreground + ",size:%(size)d" % self.faces)
				# Class name definition
				self.StyleSetSpec(stc.STC_P_CLASSNAME, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)
				# Function or method name definition
				self.StyleSetSpec(stc.STC_P_DEFNAME, "back:" + function_background + ",fore:" + function_foreground + ",bold,size:%(size)d" % self.faces)
				# Operators
				self.StyleSetSpec(stc.STC_P_OPERATOR, "back:" + keyword_background + ",fore:" + keyword_operator +",bold,size:%(size)d" % self.faces)
				# Identifiers
				self.StyleSetSpec(stc.STC_P_IDENTIFIER, "back:" + text_background + ",fore:" + text_foreground + ",face:%(helv)s,size:%(size)d" % self.faces)
				# Comment-blocks
				self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, "back:" + comment_background + ",fore:" + comment_foreground + ",size:%(size)d" % self.faces)
				# End of line where string is not closed
				self.StyleSetSpec(stc.STC_P_STRINGEOL, "back:" + invisibles_background + ", fore:" + invisibles_foreground + ",face:%(mono)s,eol,size:%(size)d" % self.faces)

			# ===========================================================
			# Html Styles
			# ===========================================================
			if fileExtension == '.html' or fileExtension == '.htm' or fileExtension == '.tmTheme':

				#print('Styling as HTML')

				# Default (doesnt style the tags, only text between tags and whitespace)
				self.StyleSetSpec(stc.STC_H_DEFAULT, "back:" + text_background + ",fore:" + text_foreground +" ,face:%(helv)s,size:%(size)d" % self.faces)

				# Comments
				self.StyleSetSpec(stc.STC_H_COMMENT, "back:" + comment_background + ",fore:" + comment_foreground + ",face:%(other)s,size:%(size)d" % self.faces)

				# stc.STC_H_ENTITY
				#self.StyleSetSpec(stc.STC_H_ENTITY, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)

				# Embedded ASP Delimiters <%%>
				# self.StyleSetSpec(stc.STC_H_ASP, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)
				self.StyleSetSpec(stc.STC_H_ASP, "back:" + keyword_background + ",fore:" + keyword_foreground + ",bold,size:%(size)d" % self.faces)

				# Number
				#self.StyleSetSpec(stc.STC_H_NUMBER, "back:" + text_background + ",fore:" + text_foreground + ",size:%(size)d" % self.faces)
				self.StyleSetSpec(stc.STC_H_NUMBER, "back:" + comment_background + ",fore:" + comment_foreground + ",face:%(other)s,size:%(size)d" % self.faces)

				# STC_H_TAGUNKNOWN = stc.STC_H_TAGUNKNOWN
				self.StyleSetSpec(stc.STC_H_TAGUNKNOWN, "back:" + text_background + ",fore:" + text_foreground +" ,face:%(helv)s,size:%(size)d" % self.faces)

				#####################

				# Tag not working, must i let the editor know what are tags first?
				#self.StyleSetSpec(stc.STC_H_TAG, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)

				#'''
				# STC_H_ATTRIBUTE = stc.STC_H_ATTRIBUTE
				#self.StyleSetSpec(stc.STC_H_ATTRIBUTE, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)

				# styles just the attributes, not the whitespace inside a tag or values or anything else.
				# STC_H_ATTRIBUTEUNKNOWN = stc.STC_H_ATTRIBUTEUNKNOWN
				#self.StyleSetSpec(stc.STC_H_ATTRIBUTEUNKNOWN, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)

				# STC_H_NUMBER = stc.STC_H_NUMBER
				self.StyleSetSpec(stc.STC_H_NUMBER, "back:red,fore:white,bold,underline,size:%(size)d" % self.faces)

				# STC_H_DOUBLESTRING = stc.STC_H_DOUBLESTRING
				self.StyleSetSpec(stc.STC_H_DOUBLESTRING, "back:" + string_background + ",fore:" + string_foreground + ",bold,size:%(size)d" % self.faces)

				# This works on single quoted strings.
				# STC_H_SINGLESTRING = stc.STC_H_SINGLESTRING
				self.StyleSetSpec(stc.STC_H_SINGLESTRING, "back:" + string_background + ",fore:" + string_foreground + ",bold,size:%(size)d" % self.faces)

				# STC_H_OTHER = stc.STC_H_OTHER
				#self.StyleSetSpec(stc.STC_H_OTHER, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)

				# STC_H_ENTITY =_stc.STC_H_ENTITY
				self.StyleSetSpec(stc.STC_H_ENTITY, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)

				# STC_H_TAGEND = stc.STC_H_TAGEND
				#self.StyleSetSpec(stc.STC_H_TAGEND, "back:yellow,fore:green,bold,underline,size:%(size)d" % self.faces)

				# STC_H_XMLSTART = stc.STC_H_XMLSTART
				self.StyleSetSpec(stc.STC_H_XMLSTART, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)
				# STC_H_XMLEND = stc.STC_H_XMLEND
				self.StyleSetSpec(stc.STC_H_XMLEND, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)

				# STC_H_SCRIPT = stc.STC_H_SCRIPT
				self.StyleSetSpec(stc.STC_H_SCRIPT, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)
				# STC_H_ASP = stc.STC_H_ASP
				self.StyleSetSpec(stc.STC_H_ASP, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)

				# asp background below here somewhere
				# STC_H_ASPAT = stc.STC_H_ASPAT
				self.StyleSetSpec(stc.STC_H_ASPAT, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)
				# STC_H_CDATA = stc.STC_H_CDATA
				self.StyleSetSpec(stc.STC_H_CDATA, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)
				# STC_H_QUESTION = stc.STC_H_QUESTION
				self.StyleSetSpec(stc.STC_H_QUESTION, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)
				# STC_H_VALUE = stc.STC_H_VALUE
				self.StyleSetSpec(stc.STC_H_VALUE, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)
				# STC_H_XCCOMMENT = stc.STC_H_XCCOMMENT
				self.StyleSetSpec(stc.STC_H_XCCOMMENT, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)
				# STC_H_SGML_DEFAULT = stc.STC_H_SGML_DEFAULT
				self.StyleSetSpec(stc.STC_H_SGML_DEFAULT, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)
				# STC_H_SGML_COMMAND = stc.STC_H_SGML_COMMAND
				self.StyleSetSpec(stc.STC_H_SGML_COMMAND, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)
				# STC_H_SGML_1ST_PARAM = stc.STC_H_SGML_1ST_PARAM
				self.StyleSetSpec(stc.STC_H_SGML_1ST_PARAM, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)
				# STC_H_SGML_DOUBLESTRING = stc.STC_H_SGML_DOUBLESTRING
				self.StyleSetSpec(stc.STC_H_SGML_DOUBLESTRING, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)
				# STC_H_SGML_SIMPLESTRING = stc.STC_H_SGML_SIMPLESTRING
				self.StyleSetSpec(stc.STC_H_SGML_SIMPLESTRING, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)
				# STC_H_SGML_ERROR = stc.STC_H_SGML_ERROR
				self.StyleSetSpec(stc.STC_H_SGML_ERROR, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)
				# STC_H_SGML_SPECIAL = stc.STC_H_SGML_SPECIAL
				self.StyleSetSpec(stc.STC_H_SGML_SPECIAL, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)
				# STC_H_SGML_ENTITY = stc.STC_H_SGML_ENTITY
				self.StyleSetSpec(stc.STC_H_SGML_ENTITY, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)
				# STC_H_SGML_COMMENT = stc.STC_H_SGML_COMMENT
				self.StyleSetSpec(stc.STC_H_SGML_COMMENT, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)
				# STC_H_SGML_1ST_PARAM_COMMENT = stc.STC_H_SGML_1ST_PARAM_COMMENT
				self.StyleSetSpec(stc.STC_H_SGML_1ST_PARAM_COMMENT, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)
				# STC_H_SGML_BLOCK_DEFAULT = stc.STC_H_SGML_BLOCK_DEFAULT
				self.StyleSetSpec(stc.STC_H_SGML_BLOCK_DEFAULT, "back:" + classname_background + ",fore:" + classname_foreground + ",bold,underline,size:%(size)d" % self.faces)
				#'''
			# register some images for use in the AutoComplete box.
			self.RegisterImage(2, wx.ArtProvider.GetBitmap(wx.ART_NEW, size=(16,16)))
			self.RegisterImage(3, wx.ArtProvider.GetBitmap(wx.ART_COPY, size=(16,16)))

	# lazy way to avoid keyerrors when parsing a theme
	def clean(self, thisGroup, thisEntry):
		try:
			x = thisGroup[thisEntry]
		except KeyError:
			x = ''
		return x

	def OnMarginClick(self, evt):
		# fold and unfold as needed
		if evt.GetMargin() == 2:
			if evt.GetShift() and evt.GetControl():
				self.FoldAll()
			else:
				lineClicked = self.LineFromPosition(evt.GetPosition())
				if self.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG:
					if evt.GetShift():
						self.SetFoldExpanded(lineClicked, True)
						self.Expand(lineClicked, True, True, 1)
					elif evt.GetControl():
						if self.GetFoldExpanded(lineClicked):
							self.SetFoldExpanded(lineClicked, False)
							self.Expand(lineClicked, False, True, 0)
						else:
							self.SetFoldExpanded(lineClicked, True)
							self.Expand(lineClicked, True, True, 100)
					else:
						self.ToggleFold(lineClicked)

	def FoldAll(self):
		lineCount = self.GetLineCount()
		expanding = True

		# find out if we are folding or unfolding
		for lineNum in range(lineCount):
			if self.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG:
				expanding = not self.GetFoldExpanded(lineNum)
				break
		lineNum = 0
		while lineNum < lineCount:
			level = self.GetFoldLevel(lineNum)
			if level & stc.STC_FOLDLEVELHEADERFLAG and \
			(level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE:
				if expanding:
					self.SetFoldExpanded(lineNum, True)
					lineNum = self.Expand(lineNum, True)
					lineNum = lineNum - 1
				else:
					lastChild = self.GetLastChild(lineNum, -1)
					self.SetFoldExpanded(lineNum, False)
					if lastChild > lineNum:
						self.HideLines(lineNum+1, lastChild)
			lineNum = lineNum + 1

	def Expand(self, line, doExpand, force=False, visLevels=0, level=-1):
		lastChild = self.GetLastChild(line, level)
		line = line + 1
		while line <= lastChild:
			if force:
				if visLevels > 0:
					self.ShowLines(line, line)
				else:
					self.HideLines(line, line)
			else:
				if doExpand:
					self.ShowLines(line, line)
			if level == -1:
				level = self.GetFoldLevel(line)
			if level & stc.STC_FOLDLEVELHEADERFLAG:
				if force:
					if visLevels > 1:
						self.SetFoldExpanded(line, True)
					else:
						self.SetFoldExpanded(line, False)
					line = self.Expand(line, doExpand, force, visLevels-1)
				else:
					if doExpand and self.GetFoldExpanded(line):
						line = self.Expand(line, True, force, visLevels-1)
					else:
						line = self.Expand(line, False, force, visLevels-1)
			else:
				line = line + 1
		return line

	'''
	===================================================================
	My very ignorant first attempt at keyword autocomplete.
	Its ugly, and hacky, but the list seems to be showing up somewhat right.

	todo - review the autocomp specs at 
	http://www.yellowbrain.com/stc/autocomp.html
	and rewrite this rubbish.
	===================================================================
	'''

	# Generic function that takes a string and looks through a listOfStrings
	# to see if the sting is found in the list. I threw this together very
	# quickly so it probably contains errors and i sure its written poorly.

	# THIS IS ONLY BEING USED AS A TRIGGER TO SHOW OR HIDE THE MENU
	# THEN ONKEYUP HANDLES EVERYTHING ELSE, SO CAN THIS BE SIMPLIFIED?

	def showAutoCompleteMenu(self):

		partialString = self.currentWord.lower()
		listOfStrings = keyword.kwlist[:]

		# length of the item were searching for
		searchItemLength = len(partialString)

		# When Auto Complete menu is already open, skip this.

		# It would also be useful to determine if the text being typed is
		# is inside a comment, in which case we shouldnt show Auto Complete.

		if self.AutoCompActive() == False:
			searchItemLength = len(partialString)

			for listItem in listOfStrings:
				listItemLength = len(listItem)
				try:
					if partialString == listItem[:searchItemLength]:
						return True
				except:
					return False
		else:
			return False # autocomplete already visible

	# Asks findPartialStringInList() if its ok to 
	# show the auto complete list, if so it shows it.
	def OnKeyUp(self, event):
		key = event.GetKeyCode()
		if key < 256:
			# If space or tab or no text clear word buffer.
			if (key == 32 or key == 9) or (self.GetText()==''):
				self.currentWord = ''
			else:
				# Do the keyword popup if text typed since the last 
				# blank space is in the list.
				self.currentWord = self.currentWord + chr(key)
				if self.showAutoCompleteMenu() == True:
					kw = keyword.kwlist[:]
					kw.sort()
					self.AutoCompSetIgnoreCase(True)
					self.AutoCompShow(len(self.currentWord), " ".join(kw))

	# When I get ready to get into this
	# http://macromates.com/textmate/manual/language_grammars
	def OnKeyPressed(self, event):
			if self.CallTipActive():
					self.CallTipCancel()
			key = event.GetKeyCode()

			if key == 32 and event.ControlDown():
				# Tips
				pos = self.GetCurrentPos()
				if event.ShiftDown():
					self.CallTipSetBackground("white")
					self.CallTipSetForeground("black")
					self.CallTipShow(pos, 'lots of of text: blah, blah, blah\n'
													 'show some suff, maybe parameters..\n'
													 'fubar(param1, param2)')

			else:
					event.Skip()
